package connectors;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;

import javax.swing.JOptionPane;

import model.DocumentEA;
import model.EA2ExcelMapping;
import model.ExcelCell;
import model.MainModel;
import model.SAPObject;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import utils.ControllerUtils;
import utils.FileUtils;
import utils.MessageHandler;
import utils.ObjectUtils;
import utils.StringUtils;

public class ExcelConnector {

	private String inputFilePath;
	private String outputFilePath;
	public String[][] table;
	private MainModel model;
	private XSSFWorkbook workbook;
	private XSSFSheet sheet;
	private final String separator = ";";
	private final int columnHeaderLineNumber = 2;
	private BufferedReader br;

	public ExcelConnector(MainModel mainModel, String importFilePath,
			String outputFilePath) {

		if (mainModel != null && FileUtils.exist(importFilePath)) {
			this.model = mainModel;
			this.inputFilePath = importFilePath;
			if (StringUtils.isXLSXFile(importFilePath)) {

				try {

					FileInputStream file = new FileInputStream(new File(
							inputFilePath));

					// Get the workbook instance for XLS file
					workbook = new XSSFWorkbook(file);

					// Get first sheet from the workbook
					sheet = workbook.getSheetAt(0);

				} catch (FileNotFoundException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}
			} else if (StringUtils.isCSVFile(importFilePath)) {

				// FIXME:this code is implemented to cut the
				// time requisites - later through
				// reflection
				ArrayList<EA2ExcelMapping> mapping = new ArrayList<EA2ExcelMapping>();
				mapping.add(new EA2ExcelMapping("Name", 0));
				mapping.add(new EA2ExcelMapping("Version", 1));
				mapping.add(new EA2ExcelMapping("Type", 2));
				mapping.add(new EA2ExcelMapping("newOrChange", 3));
				populateModelFromCSV(mapping,
						DocumentEA.class.getCanonicalName());
				// FIXME:END

			} else {

				JOptionPane.showMessageDialog(null, "", "Error",
						JOptionPane.ERROR_MESSAGE);
				return;
			}

		} else {
			JOptionPane.showMessageDialog(null,
					"Model is not Specified or file does not exist", "Error",
					JOptionPane.ERROR_MESSAGE);
			return;
		}
	}

	public void populateModelFromXLSX(ArrayList<EA2ExcelMapping> mapping) {
		if (sheet != null) {

			Iterator<Row> rowIterator = sheet.iterator();
			while (rowIterator.hasNext()) {
				Row row = rowIterator.next();

				// For each row, iterate through each columns
				Iterator<Cell> cellIterator = row.cellIterator();

				DocumentEA docEA = new DocumentEA();
				while (cellIterator.hasNext()) {
					for (EA2ExcelMapping map : mapping) {

						XSSFCell cell = (XSSFCell) cellIterator.next();

						if (cell.getColumnIndex() == map.getExcelColumn()) {
							// / (processCell(cell));
						}
						if (cell.getColumnIndex() == 1) {
							docEA.setVersion(processCell(cell));
						}
						if (cell.getColumnIndex() == 2) {
							docEA.setType(processCell(cell));
						}
						if (cell.getColumnIndex() == 3) {
							docEA.setNewOrChange(processCell(cell));
						}
					}

				}
				if (ObjectUtils.propsNotNullandEmpty(docEA)) {
					model.getEADocumentModel().add(docEA);
				}
			}
		}
	}

	public void populateSAPPartModelFromXLSX(ArrayList<SAPObject> mapping) {
		if (sheet != null) {

			Iterator<Row> rowIterator = sheet.iterator();
			while (rowIterator.hasNext()) {
				Row row = rowIterator.next();

				// For each row, iterate through each columns
				Iterator<Cell> cellIterator = row.cellIterator();

				SAPObject SAPO = new SAPObject();
				while (cellIterator.hasNext()) {
					for (SAPObject map : mapping) {

						XSSFCell cell = (XSSFCell) cellIterator.next();
						// TODO: this part should be changed in the future to
						// work as is because of inconsistance for general task
						// sap OBJECT SHOULD BE erweitert

						if (cell.getColumnIndex() == 1) {
							SAPO.setName(processCell(cell));
						}
						if (cell.getColumnIndex() == 2) {
							SAPO.setPrimary_key(Boolean
									.valueOf(processCell(cell)));
						}
						if (cell.getColumnIndex() == 3) {
							SAPO.setNotes(processCell(cell));
						}
					}

				}
				if (ObjectUtils.propsNotNullandEmpty(SAPO)) {
					model.getSAPObjectModel().add(SAPO);
				}
			}
		}
	}

	public void populateModelFromCSV(ArrayList<EA2ExcelMapping> mapping,
			String canonicalClassName) {
		if (mapping != null) {

			File file1 = new File(inputFilePath);

			try {
				br = new BufferedReader(new FileReader(file1));

				int lineCounter = 0;
				System.out.println("start reading");
				String line = "";
				// FIXME: this part must be supervised once more
				ArrayList<DocumentEA> eadoc = MainModel.getEADocumentModel();
				ArrayList<ExcelCell> excel = new ArrayList<ExcelCell>();
				while ((line = br.readLine()) != null) {

					if (lineCounter == 1) {
						String[] namearr = line.split(separator);
						for (int i = 0; i < namearr.length; i++) {
							String value = namearr[i];
							if (value.startsWith("PL.")) {
								excel.add(new ExcelCell(lineCounter, i, value));
							}
						}
					}
					// FIXME: must be fixed in following versions
					if (lineCounter < 3) {
						lineCounter++;
						continue;
					}

					// FIXME: creation a doc must be resolved via reflection
					DocumentEA doc = new DocumentEA();
					String[] splitted = line.split(separator);
					for (int i = 0; i < splitted.length; i++) {
						String curr = splitted[i];
						if (!curr.trim().equals("")) {
							for (EA2ExcelMapping map : mapping) {
								if (map.getExcelColumn() == i) {
									ObjectUtils.setField(doc,
											map.getEAElementType(), curr);
									System.out.println("Element added");
								}
							}

						}

						if (curr.trim().equals("X")) {
							for (ExcelCell ex : excel) {
								if (ex.getColIndex() == i) {
									doc.getMappingObjectNames().add(
											ex.getCellValue());
									System.out
											.println("This one has been added and finished");
								}
							}
						}

					}
					eadoc.add(doc);
					lineCounter++;
				}

				br.close();
				System.out.println("ends reading");
				System.out.println("deleting null objects");
				deleteNullObjects(eadoc);
				System.out.println("Objects has been deleted");

			} catch (IOException ex) {
				MessageHandler.showSingleError(ex.getMessage());
			}

		}
	}

	private String processCell(XSSFCell cell) {
		switch (cell.getCellType()) {
		case Cell.CELL_TYPE_BOOLEAN: {
			return StringUtils.SafeString(String.valueOf(cell
					.getBooleanCellValue()));
		}
		case Cell.CELL_TYPE_NUMERIC: {
			return StringUtils.SafeString(String.valueOf(cell
					.getNumericCellValue()));
		}
		case Cell.CELL_TYPE_STRING: {
			return StringUtils.SafeString(String.valueOf(cell
					.getStringCellValue()));
		}
		default: {
			return "";
		}
		}

	}

	public void deleteNullObjects(ArrayList<DocumentEA> mdl) {
		ArrayList<DocumentEA> toDelete = new ArrayList<DocumentEA>();
		for (DocumentEA doc : mdl) {
			if (doc.getName() == null) {
				toDelete.add(doc);
			}
		}
		for (DocumentEA docs : toDelete) {
			mdl.remove(docs);
		}

	}

	public String getInputFilePath() {
		return inputFilePath;
	}

	public void setInputFilePath(String inputFilePath) {
		this.inputFilePath = inputFilePath;
	}

	public String getOutputFilePath() {
		return outputFilePath;
	}

	public void setOutputFilePath(String outputFilePath) {
		this.outputFilePath = outputFilePath;
	}

}
